\section{Shell 变量}
declare或typeset是一样的功能，就是在『声明变量的类型』。如果使用declare后面并没有接任何参数，那么bash就会主动的将所有的变量名称与内容通通叫出来，就好像使用set一样啦！那么declare还有什么语法呢？看看先：

[liushuai@liushuai-PC ~]\$ 
declare [-aixr] variable 
选项与参数：
\begin{itemize}
    \item -a ：将后面名为variable 的变量定义成为阵列(array) 类型              
    \item -i ：将后面名为variable 的变量定义成为整数数字(integer) 类型        
    \item -x ：用法与export 一样，就是将后面的variable 变成环境变量；         
    \item -r ：将变量设定成为readonly 类型，该变量不可被更改内容，也不能unset 
\end{itemize}
范例一：让变量sum进行100+300+50的加总结果 
\begin{bash}
[liushuai@liushuai-PC ~]$ sum=100+300+50 
[liushuai@liushuai-PC ~]$ echo ${sum} 
100+300+50   <==咦！怎么没有帮我计算加总？因为这是文字型态的变量属性啊！
[liushuai@liushuai-PC ~]$ declare -i sum=100+300+50 
[liushuai@liushuai-PC ~]$ echo ${sum} 
450          <==了乎？？
\end{bash}
由于在预设的情况底下， bash 对于变量有几个基本的定义：

变量类型预设为『字串』，所以若不指定变量类型，则1+2 为一个『字串』而不是『计算式』。所以上述第一个执行的结果才会出现那个情况的；
bash 环境中的数值运算，预设最多仅能到达整数形态，所以1/3 结果是0；
现在你晓得为啥你需要进行变量声明了吧？如果需要非字串类型的变量，那就得要进行变量的声明才行啦！底下继续来玩些其他的declare 功能。

范例二：将sum变成环境变量 
\begin{bash}
[liushuai@liushuai-PC ~]$ declare -x sum 
[liushuai@liushuai-PC ~]$ export | grep sum 
declare -ix sum="450"   <==果然出现了！包括有i与x的声明！
\end{bash}
范例三：让sum变成唯读属性，不可更动！
\begin{bash}
[liushuai@liushuai-PC ~]$ declare -r sum 
[liushuai@liushuai-PC ~]$ sum=testing 
-bash: sum: readonly variable   <==老天爷～不能改这个变量了！
\end{bash}
范例四：让sum变成非环境变量的自定义变量吧！
\begin{bash}
[liushuai@liushuai-PC ~]$ declare +x sum   <==将-变成+可以进行『取消』动作 
[liushuai@liushuai-PC ~]$ declare -p sum   <== -p可以单独列出变量的类型 
\end{bash}
declare -ir sum="450" <==看吧！只剩下i, r的类型，不具有x！
declare 也是个很有用的功能～尤其是当我们需要使用到底下的阵列功能时， 他也可以帮我们声明阵列的属性喔！不过，老话一句，阵列也是在shell script 比较常用的啦！比较有趣的是，如果你不小心将变量设定为『唯读』，通常得要登出再登入才能复原该变量的类型了！
阵列(array) 变量类型
某些时候，我们必须使用阵列来声明一些变量，这有什么好处啊？在一般人的使用上， 果然是看不出来有什么好处的！不过，如果您曾经写过程序的话，那才会比较了解阵列的意义～ 阵列对写数值程序的设计师来说，可是不能错过学习的重点之一哩！好！不唆～ 那么要如何设定阵列的变量与内容呢？在bash 里头，阵列的设定方式是：

var[index]=content
意思是说，我有一个阵列名称为var ，而这个阵列的内容为var[1]=小明， var[2]=大明， var[3]=好明.... 等等，那个index 就是一些数字啦，重点是用中刮号([ ]) 来设定的。目前我们bash 提供的是一维阵列。老实说，如果您不必写一些复杂的程序， 那么这个阵列的地方，可以先略过，等到有需要再来学习即可！因为要制作出阵列， 通常与循环或者其他判断式交互使用才有比较高的存在意义！

范例：设定上面提到的var[1] ～ var[3]的变量。
\begin{bash}
[liushuai@liushuai-PC ~]$ var[1]="small min" 
[liushuai@liushuai-PC ~]$ var[2]="big min" 
[liushuai@liushuai-PC ~]$ var[3]="nice min" 
[liushuai @liushuai-PC ~]$ echo "${var[1]}, ${var[2]}, ${var[3]}"
small min, big min, nice min
\end{bash}
阵列的变量类型比较有趣的地方在于『读取』，一般来说，建议直接以\${阵列}的方式来读取，比较正确无误的啦！这也是为啥鸟哥一开始就建议你使用\${变量}来记忆的原因！



Top
10.2.7 与档案系统及程序的限制关系： ulimit
想像一个状况：我的Linux主机里面同时登入了十个人，这十个人不知怎么搞的，同时开启了100个档案，每个档案的大小约10MBytes ，请问一下，我的Linux主机的记忆体要有多大才够？10*100*10 = 10000 MBytes = 10GBytes ...老天爷，这样，系统不挂点才有鬼哩！为了要预防这个情况的发生，所以我们的bash是可以『限制使用者的某些系统资源』的，包括可以开启的档案数量，可以使用的CPU时间，可以使用的记忆体总量等等。如何设定？用ulimit吧！
\begin{bash}
[liushuai@liushuai-PC ~]$ ulimit [-SHacdfltu] [配额] 
选项与参数：
-H ：hard limit ，严格的设定，必定不能超过这个设定的数值；
-S ：soft limit ，警告的设定，可以超过这个设定值，但是若超过则有警告讯息。
      在设定上，通常soft 会比hard 小，举例来说，soft 可设定为80 而hard 
      设定为100，那么你可以使用到90 (因为没有超过100)，但介于80~100 之间时，
      系统会有警告讯息通知你！
-a ：后面不接任何选项与参数，可列出所有的限制额度；
-c ：当某些程序发生错误时，系统可能会将该程序在记忆体中的资讯写成档案(除错用)，
      这种档案就被称为核心档案(core file)。此为限制每个核心档案的最大容量。
-f ：此shell 可以建立的最大档案容量(一般可能设定为2GB)单位为Kbytes
-d ：程序可使用的最大断裂记忆体(segment)容量；
-l ：可用于锁定(lock) 的记忆体量
-t ：可使用的最大CPU 时间(单位为秒)
-u ：单一使用者可以使用的最大程序(process)数量。
\end{bash}
范例一：列出你目前身份(假设为一般帐号)的所有限制文件数值 
\begin{bash}
[liushuai@liushuai-PC ~]$ ulimit -a 
core file size (blocks, -c) 0           <==只要是0就代表没限制
data seg size (kbytes, -d) unlimited
scheduling priority (-e) 0
file size (blocks, -f) unlimited   <==可建立的单一档案的大小
pending signals (-i) 4903
max locked memory (kbytes, -l) 64
max memory size (kbytes, -m) unlimited
open files (-n) 1024        <==同时可开启的档案数量
pipe size (512 bytes, -p) 8
POSIX message queues (bytes, -q) 819200
real-time priority (-r) 0
stack size (kbytes, -s) 8192
cpu time (seconds, -t) unlimited
max user processes (-u) 4096
virtual memory (kbytes, -v) unlimited
file locks (-x) unlimited
\end{bash}
范例二：限制使用者仅能建立10MBytes以下的容量的档案 
\begin{bash}
[liushuai@liushuai-PC ~]$ ulimit -f 10240 
[liushuai@liushuai-PC ~]$ ulimit -a | grep 'file size'
core file size (blocks, -c) 0
file size (blocks, -f) 10240 <==最大量为10240Kbyes，相当10Mbytes

[liushuai@liushuai-PC ~]$ dd if=/dev/zero of=123 bs=1M count=20 
File size limit exceeded (core dumped) <==尝试建立20MB的档案，结果失败了！

[liushuai@liushuai-PC ~]$ rm 123   <==赶快将这个档案删除！同时你得要登出再次的登入才能解开10M的限制
\end{bash}
还记得我们在第七章Linux磁碟档案系统里面提到过，单一filesystem能够支援的单一档案大小与block的大小有关。但是档案系统的限制容量都允许的太大了！如果想要让使用者建立的档案不要太大时，我们是可以考虑用ulimit来限制使用者可以建立的档案大小喔！利用ulimit -f就可以来设定了！例如上面的范例二，要注意单位喔！单位是Kbytes。若改天你一直无法建立一个大容量的档案，记得瞧一瞧ulimit的资讯喔！

Tips
鸟哥的图示 想要复原ulimit的设定最简单的方法就是登出再登入，否则就是得要重新以ulimit设定才行！不过，要注意的是，一般身份使用者如果以ulimit设定了-f的档案大小，那么他『只能继续减小档案容量，不能增加档案容量喔！』另外，若想要管控使用者的ulimit限值，可以参考第十三章的pam的介绍。


Top
10.2.8 变量内容的删除、取代与替换(Optional)
变量除了可以直接设定来修改原本的内容之外，有没有办法透过简单的动作来将变量的内容进行微调呢？举例来说，进行变量内容的删除、取代与替换等！是可以的！我们可以透过几个简单的小步骤来进行变量内容的微调喔！底下就来试试看！

变量内容的删除与取代
变量的内容可以很简单的透过几个咚咚来进行删除喔！我们使用PATH 这个变量的内容来做测试好了。请你依序进行底下的几个例子来玩玩，比较容易感受的到鸟哥在这里想要表达的意义：

范例一：先让小写的path自定义变量设定的与PATH内容相同 
\begin{bash}
[liushuai@liushuai-PC ~]$ path=${PATH} 
[liushuai@liushuai-PC ~]$ echo ${path} 
/usr/local/bin: / usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin:/home/liushuai/bin
\end{bash}
范例二：假设我不喜欢local/bin，所以要将前1个目录删除掉，如何显示？
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${path#/*local/bin:}
/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin:/home/liushuai/bin
\end{bash}
上面这个范例很有趣的！他的重点可以用底下这张表格来说明：
\begin{bash}
${ variable#/*local/bin: } 
   上面的特殊字体部分是关键字！用在这种删除模式所必须存在的

${ variable #/*local/bin:}
    这就是原本的变量名称，以上面范例二来说，这里就填写path这个『变量名称』啦！

${variable # /*local/bin:}
    这是重点！代表『从变量内容的最前面开始向右删除』，且仅删除最短的那个

${variable# /*local/bin: }
    代表要被删除的部分，由于#代表由前面开始删除，所以这里便由开始的/写起。
   需要注意的是，我们还可以透过通配符* 来取代0 到无穷多个任意字符

   以上面范例二的结果来看， path这个变量被删除的内容如下所示：
/usr/local/bin: /usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/. local/bin:/home/liushuai/bin
很有趣吧！这样了解了# 的功能了吗？接下来让我们来看看底下的范例三！
\end{bash}
范例三：我想要删除前面所有的目录，仅保留最后一个目录 
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${path#/*:}
/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin:/home/liushuai/bin
# 由于一个# 仅删除掉最短的那个，因此他删除的情况可以用底下的删除线来看：
# /usr/local/bin: /usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin:/home/liushuai/bin

[liushuai@liushuai-PC ~]$ echo ${path##/*:}
/home/liushuai/bin
# 嘿！多加了一个# 变成## 之后，他变成『删除掉最长的那个文件』！亦即是：
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin: /home/liushuai/bin
\end{bash}
非常有趣！不是吗？因为在PATH 这个变量的内容中，每个目录都是以冒号『:』隔开的， 所以要从头删除掉目录就是介于斜线(/) 到冒号(:) 之间的文件！但是PATH 中不止一个冒号(:) 啊！所以\# 与\#\# 就分别代表：

\# ：符合取代文字的『最短的』那一个；
\#\#：符合取代文字的『最长的』那一个
上面谈到的是『从前面开始删除变量内容』，那么如果想要『从后面向前删除变量内容』呢？这个时候就得使用百分比(\%) 符号了！来看看范例四怎么做吧！

范例四：我想要删除最后面那个目录，亦即从:到bin为止的字串 
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${path%:*bin}
/usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin
#注意啊！最后面一个目录不见去！
#这个%符号代表由最后面开始向前删除！所以上面得到的结果其实是来自如下：
# /usr/local/bin:/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin :/home/liushuai/bin
\end{bash}
范例五：那如果我只想要保留第一个目录呢？
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${path%%:*bin}
/usr/local/bin
# 同样的， %% 代表的则是最长的符合字串，所以结果其实是来自如下：
# /usr/local/bin :/usr/bin:/usr/local/sbin:/usr/sbin:/home/liushuai/.local/bin:/home/liushuai/bin
由于我是想要由变量内容的后面向前面删除，而我这个变量内容最后面的结尾是『/home/liushuai/bin』， 所以你可以看到上面我删除的文件最终一定是『bin』，亦即是『:*bin』那个* 代表通配符！至于% 与%% 的意义其实与# 及## 类似！这样理解否？
\end{bash}
例题：
假设你是liushuai ，那你的MAIL 变量应该是/var/spool/mail/liushuai 。假设你只想要保留最后面那个档名(liushuai)， 前面的目录名称都不要了，如何利用\$MAIL 变量来达成？
答：
题意其实是这样『/var/spool/mail/ liushuai』，亦即删除掉两条斜线间的所有文件(最长符合)。这个时候你就可以这样做即可：
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${MAIL##/*/}
\end{bash}
相反的，如果你只想要拿掉档名，保留目录的名称，亦即是『/var/spool/mail /liushuai』 (最短符合)。但假设你并不知道结尾的字母为何，此时你可以利用通配符来处理即可，如下所示：
\begin{bash}
[liushuai@liushuai-PC ~]$ echo ${MAIL%/*}
\end{bash}
了解了删除功能后，接下来谈谈取代吧！继续玩玩范例六！

假设path中的变量如下:
\begin{bash}
$ echo $path
/home/liushuai/anaconda3/bin:/home/liushuai/google-cloud-sdk/bin:/usr/local/opencv:/home/liushuai/vnc:/home/liushuai/anaconda3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/local/texlive/2017/bin/x86_64-linux

\end{bash}
下边对\Textinline{/home/liushuai/anaconda3/bin:}进行删除:

\begin{bash}
$ echo ${path#/*:}
/home/liushuai/google-cloud-sdk/bin:/usr/local/opencv:/home/liushuai/vnc:/home/liushuai/anaconda3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/local/texlive/2017/bin/x86_64-linux 
\end{bash}
保留最后一个环境变量:
\begin{bash}
$ echo ${path##/*:}
/usr/local/texlive/2017/bin/x86_64-linux 
\end{bash}
\%表示从后向前删除，最短匹配，\%\%表示从后向前删除，最长匹配。

从后向前删除到第一个冒号。
\begin{bash}
$ echo ${path%/*:}
/home/liushuai/anaconda3/bin:/home/liushuai/google-cloud-sdk/bin:/usr/local/opencv:/home/liushuai/vnc:/home/liushuai/anaconda3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/local/texlive/2017/bin/x86_64-linux 
\end{bash}
从后向前删除到第一个冒号(未完成)。
\begin{bash}
取代path变量中的第一个bin为BIN。
$ echo ${path/bin/BIN}
/home/liushuai/anaconda3/BIN:/home/liushuai/google-cloud-sdk/bin:/usr/local/opencv:/home/liushuai/vnc:/home/liushuai/anaconda3/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games:/usr/local/texlive/2017/bin/x86_64-linux
\end{bash}
渠道path变量中所有的bin为BIN。
\begin{bash}
$echo ${path//bin/BIN}
/home/liushuai/anaconda3/BIN:/home/liushuai/google-cloud-sdk/BIN:/usr/local/opencv:/home/liushuai/vnc:/home/liushuai/anaconda3/BIN:/usr/local/BIN:/usr/BIN:/BIN:/usr/local/games:/usr/games:/usr/local/texlive/2017/BIN/x86_64-linux
d
\end{bash}
“-”加关键字表示声明变量的时候，关键字在变量没有声明的时候作为其变量值，声明后不更改它的声明值:
\begin{bash}
liushuai@liushuai-PC:~$ username=${username-root}
liushuai@liushuai-PC:~$ echo $username 
root
liushuai@liushuai-PC:~$ username="bleedingfight"
liushuai@liushuai-PC:~$ echo $username 
bleedingfight
liushuai@liushuai-PC:~$ username=${username-root}
liushuai@liushuai-PC:~$ echo $username 
bleedingfight 
\end{bash}
如果username为空将出现问题，这时候需要用:-代替:。
\begin{bash}
liushuai@liushuai-PC:~$ username=""
liushuai@liushuai-PC:~$ username=${username-root}
liushuai@liushuai-PC:~$ echo $username

liushuai@liushuai-PC:~$ username=${username:-root}
liushuai@liushuai-PC:~$ echo $username
root
\end{bash}

\begin{table}[H]
\begin{tabular}{cccc}
\toprule
变量设定方式&str没有设定时&str为空字符串&str为设定非空子串\\
\midrule
var=\$\{str-expr\}    &var=expr    &var=    &var=\$str\\

var=\$\{str:-expr\}    &var=expr    &var=expr    &var=\$str\\

var=\$\{str+expr\}    &var=    &var=expr    &var=expr\\

var=\$\{str:+expr\}    &var=    &var=    &var=expr\\

var=\$\{str=expr\}    &str=expr\par var=expr    &str不变\newline var=    &str不变\newline var=\$str\\

var=\$\{str:=expr\}    &str=expr\newline var=expr    &str=expr\newline var=expr    &str不变\newline var=\$str\\

var=\$\{str?expr\}    &expr 输出至stderr    &var=    &var=\$str\\

var=\$\{str:?expr\}    &expr 输出至stderr    &expr 输出至stderr    &var=\$str \\
\bottomrule
\end{tabular}
\end{table}
\subsection{Bash脚本介绍}
第一个脚本:
\begin{bash}
#!/bin/bash
# Program:
# This program shows “hello world！” in your screen
PATH=/bin:/sbin:/use/bin:/usr/sbin:/usr/local/bin:/usr/local/sbin:/~/bin
export PATH
echo -e "hello! \a \n"
exit 0
\end{bash}
1.带\#号的内容表示注释，第一行中的\Textinline{#!/bin/bash}表示这是bash。那么当这个程序被执行时，他就能够载入bash的相关环境设定档(一般来说就是non-login shell的\~{}/.bashrc )，并且执行bash来使我们底下的指令能够执行！这很重要的！(在很多状况中，如果没有设定好这一行，那么该程序很可能会无法执行，因为系统可能无法判断该程序需要使用什么shell来执行！)\newline
2.整个script当中，除了第一行的\#! 是用来声明shell的之外，其他的\#都是『注解』用途！所以上面的程序当中，第二行以下就是用来说明整个程序的基本文件。一般来说，建议你一定要养成说明该script的：
\begin{enumerate}
\item 内容与功能； 
\item 版本信息； 
\item 作者与联络方式； 
\item 建档日期；
\item 历史纪录等等。
\end{enumerate} 
这将有助于未来程序的改写与debug呢！

3.主要环境变量的声明：

建议务必要将一些重要的环境变量设定好， PATH与LANG (如果有使用到输出相关的信息时)是当中最重要的！如此一来，则可让我们这支程序在进行时，可以直接执行一些外部指令，而不必写绝对路径呢！比较方便啦！

4.主要程序部分\newline 
就将主要的程序写好即可！在这个例子当中，就是echo那一行啦！

5.执行成果告知(定义回传值)\newline 
是否记得我们在第十章里面要讨论一个指令的执行成功与否，可以使用 \$?这个变量来观察～ 那么我们也可以利用exit这个指令来让程序中断，并且回传一个数值给系统。在我们这个例子当中，鸟哥使用exit 0 ，这代表离开script并且回传一个0给系统，所以我执行完这个script后，若接着执行echo \$?则可得到0的值喔！更聪明的读者应该也知道了，呵呵！利用这个exit n (n是数字)的功能，我们还可以指定错误讯息，让程序变得更加的智能！

创建一个以名字加日期命名的文件:
\begin{bash}
#!/bin/bash
# 这是我的第二个脚本用来创建新的文件
# 作者:bleedingfight

PATH=/bin:/sbin:/usr/sbin:/usr/bin:/usr/local/sbin:~/bin
export PATH
now_time=$(date)
echo "今天的时间是:"$now_time
echo -e "这个脚本将创建多个文件,Linux将使用'touch'创建\n"
read -p "请输入文件的名字:" default_file
filename=${default_file:-"default_file"}
date1=$(date --date="1 days ago" +%Y%m%d)
echo "你输入的名字是$filename"
filename1=${filename}${date1}
echo "将为您创建文件${filename1}"
touch ${filename1}
\end{bash}

当我要检测系统上面某些文件或者是相关的属性时，利用test 这个指令来工作真是好用得不得了， 举例来说，我要检查/liushuai 是否存在时，使用：

\bashinline{bleedingfight@localhost$ test -e /create.sh}
执行结果并不会显示任何讯息，但最后我们可以透过\$? 或\&\& 及|| 来展现整个结果呢！例如我们在将上面的例子改写成这样：

\bashinline{[liushuai@localhost bin]$  test -e create.sh && echo "文件存在" || "文件不存在"}

\bashinline{文件存在   <==结果显示存在！}

最终的结果可以告知我们是"文件存在"还是"文件不存在"呢！那我知道-e 是测试一个『东西』在不在， 如果还想要测试一下该文件名是啥玩意儿时，还有哪些标志可以来判断的呢？呵呵！有底下这些东西喔！

测试的标志 代表意义

如test -e filename 表示存在否
\begin{table}[H]
\caption{关于某个文件名的『文件类型』判断}
\centering
\begin{tabular}{cc}
\toprule
-e  &该『文件名』是否存在？(常用)\\

\midrule
-f  &该『文件名』是否存在且为文件(file)？(常用)\\

-d  &该『文件名』是否存在且为目录(directory)？(常用)\\

-b  &该『文件名』是否存在且为一个block device 设备？\\

-c  &该『文件名』是否存在且为一个character device 设备？\\

-S  &该『文件名』是否存在且为一个Socket 文件？\\

-p  &该『文件名』是否存在且为一个FIFO (pipe) 文件？\\

-L  &该『文件名』是否存在且为一个连结档？\\
\bottomrule
\end{tabular}
\end{table}

2. 关于文件的权限侦测，如test -r filename 表示可读否(但root 权限常有例外)
\begin{table}[!h]
\centering
\begin{tabular}{cc}
\toprule
-r  &侦测该文件名是否存在且具有『可读』的权限？\\

\midrule
-w  &侦测该文件名是否存在且具有『可写』的权限？\\

-x  &侦测该文件名是否存在且具有『可执行』的权限？\\

-u  &侦测该文件名是否存在且具有『SUID』的属性？\\

-g  &侦测该文件名是否存在且具有『SGID』的属性？\\

-k  &侦测该文件名是否存在且具有『Sticky bit』的属性？\\

-s  &侦测该文件名是否存在且为『非空白文件』？\\
\bottomrule
\end{tabular}
\end{table}

3. 两个文件之间的比较，如： test file1 -nt file2
\begin{table}[!h]
\centering
\begin{tabular}{m{2cm}m{8cm}}
\toprule
-nt &(newer than)判断file1 是否比file2 新\\
\midrule

-ot &(older than)判断file1 是否比file2 旧\\

-ef &判断file1 与file2 是否为同一文件，可用在判断hard link 的判断上。主要意义在判断，两个文件是否均指向同一个inode 哩！\\
\bottomrule
\end{tabular}
\end{table}

4. 关于两个整数之间的判断，例如test n1 -eq n2
\begin{table}[H]
\centering
\caption{比较数值}
\begin{tabular}{cc}
\toprule
-eq &两数值相等(equal)\\
\midrule
-ne &两数值不等(not equal)\\

-gt &n1 大于n2 (greater than)\\

-lt &n1 小于n2 (less than)\\

-ge &n1 大于等于n2 (greater than or equal)\\

-le &n1 小于等于n2 (less than or equal)\\
\bottomrule
\end{tabular}
\end{table}
5. 判断字符串的内容
\begin{table}[!h]
\centering
\begin{tabular}{m{0.2\textwidth}|m{0.8\textwidth}}
\toprule
test -z string  &判断字串是否为0 ？若string 为空字串，则为true\\
\midrule
test -n string  &判断字串是否非为0 ？若string为空字串，则为false。
注： -n亦可省略\\

test str1 == str2 &判断str1 是否等于str2 ，若相等，则回传true\\

test str1 != str2 &判断str1 是否不等于str2 ，若相等，则回传false\\
\bottomrule
\end{tabular}
\end{table}

6. 多重条件判断，例如： test -r filename -a -x filename
\begin{table}[!h]
\centering
\begin{tabular}{m{2cm}m{8cm}}
\toprule
-a  &(and)两状况同时成立！例如test -r file -a -x file，则file 同时具有r 与 x 权限时，才回传true。\\
\midrule
-o  &(or)两状况任何一个成立！例如test -r file -o -x file，则file 具有r 或 x 
权限时，就可回传true。\\

! &反相状态，如test ! -x file ，当file 不具有x 时，回传true\\
\bottomrule
\end{tabular}
\end{table}
系统自带特殊变量：
\begin{itemize}
    \item \$\# ：代表后接的参数『个数』，以上表为例这里显示为『 4 』；
    \item "\$@" ：代表『 "\$1" "\$2" "\$3" "\$4" 』之意，每个变量是独立的(用雙引號括起來)；
    \item "\$*" ：代表『 "\$1c\$2c\$3c\$4" 』，其中 c 为分隔字符，默认为空白鍵， 所以本例中代表『 "\$1 \$2 \$3 \$4" 』之意。
\end{itemize}
OK！现在我们就利用test 来帮我们写几个简单的例子。首先，判断一下，让使用者输入一个文件名，我们判断：

这个文件是否存在，若不存在则给予一个Filename does not exist的讯息，并中断程序；
若这个文件存在，则判断他是个文件或目录，结果输出Filename is regular file或 Filename is directory
判断一下，执行者的身份对这个文件或目录所拥有的权限，并输出权限文件！
你可以先自行创作看看，然后再跟底下的结果讨论讨论。注意利用test 与\&\& 还有|| 等标志！
\subsection{if条件判断}
\begin{bash}
if [ 条件判断  ];then
    条件判断正确的时候执行指令
fi
\end{bash}
下面判断目录中是否存在test文件

多重条件判断：
\begin{bash}
#多个条件判断(if ... elif ... elif ... else)分多种不同情况执行
if [ 条件判断式一 ]; then
    当条件判断式一成立时，可以进行的指令工作内容；
elif [ 条件判断式二 ]; then
    当条件判断式二成立时，可以进行的指令工作内容；
else
    当条件判断式一与二均不成立时，可以进行的指令工作内容；
fi
\end{bash}
\subsection{case}
\begin{bash}
case  $变量名称 in   <==关键字为 case ，还有变量前有$
"第一个变量内容")   <==每个变量内容建议用双括号括起來，关键字则为小括号 )
程序段
;;            <==每个case结尾使用两个连续的分号来处理！
  "第二个变量内容")
程序段
;;
  *)                 <==最后一个变量内容都会用 * 来代表所有其他值不包含第一个变量内容和第二个变量内容的其他程序执行
exit 1
;;
esac                  <==最终的 case 结尾！`返过来来写` 思考一下！ 
\end{bash}
\subsection{函数}
\begin{bash}
function fname() {
    程序段
}
\end{bash}
\subsection{while循环}
\begin{bash}
while [ condition ]  <==中括号里的状态就是判断式
do            <==do 是循环的开始！
    程序段
done          <==done 是循环的结束
\end{bash}
\begin{bash}
until [ condition ]
do
    程序段
done
\end{bash}
\subsection{for循环}
\begin{bash}
for var in con1 con2 con3 ...
do
    程序段
done
\end{bash}
for的数值处理：
\begin{bash}
for (( 初始值; 限制值; 执行步数 ))
do
    程序段
done
\end{bash}
例如：
\begin{bash}
for( ( i=1;i<10;i=i+1 ))
do
    echo $i
done
\end{bash}
\subsection{shell debug}
sh [-nvx] 脚本
\begin{bash}
-n：不执行脚本，仅检查与发错无。
-v：在执行脚本前，先将脚本的内容输出到屏幕上。
-x：将使用到的脚本的内容显示到屏幕桑。
\end{bash}
